

package com.gs.netty.core.handler.method;



import com.gs.netty.core.annotation.CommandControllerAdvice;
import com.gs.netty.core.common.Ordered;

import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.OrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;

public class ControllerAdviceBean implements Ordered {
	/**
	 * bean对象或bean的名称
	 */
	private final Object beanOrName;

	/**
	 * 是否单例
	 */

	private final boolean isSingleton;


	/**
	 * spring 容器
	 */

	@Nullable
	private final BeanFactory beanFactory;

	/**
	 * bean的 Class 类型
	 */

	@Nullable
	private final Class<?> beanType;

	/**
	 * 实际的引用bean对象
	 */

	@Nullable
	private Object resolvedBean;

	public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable CommandControllerAdvice controllerAdvice) {
		Assert.hasText(beanName, "Bean name must contain text");
		Assert.notNull(beanFactory, "BeanFactory must not be null");
		Assert.isTrue(beanFactory.containsBean(beanName), () -> "BeanFactory [" + beanFactory +
				"] does not contain specified controller advice bean '" + beanName + "'");

		this.beanOrName = beanName;
		this.isSingleton = beanFactory.isSingleton(beanName);
		this.beanType = getBeanType(beanName, beanFactory);
//		this.beanTypePredicate = (controllerAdvice != null ? createBeanTypePredicate(controllerAdvice) :
//				createBeanTypePredicate(this.beanType));
		this.beanFactory = beanFactory;
	}

	@Nullable
	private static Class<?> getBeanType(String beanName, BeanFactory beanFactory) {
		Class<?> beanType = beanFactory.getType(beanName);
		return (beanType != null ? ClassUtils.getUserClass(beanType) : null);
	}
	@Nullable
	public Class<?> getBeanType() {
		return this.beanType;
	}


	public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
		ListableBeanFactory beanFactory = context;
		if (context instanceof ConfigurableApplicationContext) {
			// Use internal BeanFactory for potential downcast to ConfigurableBeanFactory above
			beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();
		}
		List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
		for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class)) {
			if (!ScopedProxyUtils.isScopedTarget(name)) {
				// 找到有这个注解的bean
				CommandControllerAdvice controllerAdvice = beanFactory.findAnnotationOnBean(name, CommandControllerAdvice.class);
				if (controllerAdvice != null) {

					adviceBeans.add(new ControllerAdviceBean(name, beanFactory, controllerAdvice));
				}
			}
		}
		OrderComparator.sort(adviceBeans);
		return adviceBeans;
	}

	public Object resolveBean() {
		if (this.resolvedBean == null) {
			// this.beanOrName must be a String representing the bean name if
			// this.resolvedBean is null.
			Object resolvedBean = beanFactory.getBean((String) this.beanOrName);
			// Don't cache non-singletons (e.g., prototypes).
			if (!this.isSingleton) {
				return resolvedBean;
			}
			this.resolvedBean = resolvedBean;
		}
		return this.resolvedBean;
	}

	@Override
	public int getOrder() {
		return 0;
	}

	/**
	 *  TODO 在实际项目开发这个方法不知道应用在那个业务场景，先放在这
	 * @param handlerType
	 * @return
	 */
	public boolean isApplicableToBeanType(Class<?> handlerType) {
		return true;
	}
}
